#include <U8glib.h>
//协议
#include "onenet.h"
#include "fault.h"

//网络设备
#include "net_device.h"
bool sendFlag = 1;
NET_DEVICE_CLASS NET_DEVICE;
ONENET_CLASS ONENET;
FAULT_CLASS FAULT;

U8GLIB_ST7920_128X64_1X lcd(3,9,8);

unsigned char *dataPtr;

int table[4][4] = {0};
boolean gameover = false;

int score = 0;
int total = 0;
char number[][5] = {"", "2", "4", "8", "16", "32", "64", "128",
    "256", "512", "1024", "2048",  "####"   
};

//绘制表格
void printable(){
  int left = 1;
    int top = 5;
    int spanV = 1, spanH = 1;
    int textHeight = 10, textWidth = 7;

    lcd.firstPage();
    lcd.setFont(u8g_font_7x14);
    lcd.setFontPosTop();
    do {
        // 绘制边框
        for (int i=0; i<=4; i++)
            lcd.drawHLine(left + spanH,
                top + spanV*(2*i+1) + textHeight*i + 1*i,
                10*spanH + 16*textWidth + 1*5 - spanH*2);
        for (int i=0; i<=4; i++)
            lcd.drawVLine(left + spanH*(2*i+1) + textWidth*4*i + 1*i,
                top + spanV,
                spanV*10 + textHeight*4 + 1*5 - spanV*2);

        // 绘制文本
        for (int i=0; i<4; i++)
        {
            for (int j=0; j<4; j++)
            {
                int x=left + spanH*2*(j+1) + textWidth*j*4 + 1*(j+1);
                int y=top + spanV*2*(i+1) + textHeight*i + 1*(i+1) - 2;
                lcd.drawStr(x, y, number[table[i][j]]);
            }
        }
    } while (lcd.nextPage());
  }//printale

void juWin(){
  boolean win = false;
  for(int i=0;i<4;i++){
    for(int j=0;j<4;j++){
      if(table[i][j] == 11){
        win = true;
        total = score;

          
          if(ONENET.netWork&&win == true)
        {
        //上传数据
        if(win=true)                 
        {
            
            if(sendFlag)
            {
                ONENET.OneNet_SendData(total);               //上传数据
            }
            
    
            sendFlag = !sendFlag;
        }

        //错误处理
        if(FAULT.faultType != FAULT_NONE)                  //如果错误标志被设置
        {
            FAULT.Fault_Process();                        //进入错误处理函数
        }
    }
    else
    {
        
        //网络连接 平台连接
        while(!ONENET.netWork){
        
          if(!NET_DEVICE.NET_DEVICE_Init())
              ONENET.OneNet_DevLink(ONENET.devID, ONENET.apiKey);
          
          delay(100);
        }
        if(ONENET.netWork&&win == true)
        {
        //上传数据
        if(win=true)                 
        {
            
            if(sendFlag)
            {
                ONENET.OneNet_SendData(total);               //上传数据
            }
            
    
            sendFlag = !sendFlag;
        }

        //错误处理
        if(FAULT.faultType != FAULT_NONE)                  //如果错误标志被设置
        {
            FAULT.Fault_Process();                        //进入错误处理函数
        }
    }
    }
       lcd.firstPage();
        lcd.setFont(u8g_font_ncenB14);
        lcd.setFontPosTop();
        do {
           lcd.drawStr(3,23,"YOU WIN");
        } while(lcd.nextPage());
        for(int i=4;i<=7;i++){
          if(digitalRead(i) == LOW){
              setup();
          } 
      }
      }
    }
  }
}

//操作，上下左右
boolean op(int input,boolean test=false){
  int temporary[4][4];
  boolean changed = false;
  memcpy(temporary, table, sizeof(table));
  
    switch(input){
      //UP
        case 5:
        //将所有元素上移一位
            for (int j=0; j<4; j++)
            {
                int p=0, q = 0;
                for (; q<4; q++)
                    if (temporary[q][j])
                    {
                        if (p!=q) changed=true;
                        temporary[p++][j]=temporary[q][j];
                    }
                for (; p<4; p++) temporary[p][j] = 0;
            }
          //判断能否合并
            for (int j=0; j<4; j++)
                for (int i=0; i<3; i++)
                    if (temporary[i][j] && temporary[i][j]==temporary[i+1][j])
                    {
                        score = score+temporary[i][j];
                        temporary[i][j]++;
                        temporary[i+1][j]=0;
                        changed=true;
                    }
          //有元素合并以后其他元素的位置变化
            for (int j=0; j<4; j++)
            {
                int p = 0, q = 0;
                for (; q<4; q++) if (temporary[q][j]) temporary[p++][j]=temporary[q][j];
                for (; p<4; p++) temporary[p][j] = 0;
            }
            break;
        //DOWN
        case 4:
            for (int j=0; j<4; j++)
            {
                int p = 3, q = 0;
                for (q=3; q>=0; q--)
                    if (temporary[q][j])
                    {
                        if (p!=q) changed=true;
                        temporary[p--][j]=temporary[q][j];
                    }
                for (; p>=0; p--) temporary[p][j] = 0;
            }

            for (int j=0; j<4; j++)
                for (int i=3; i>0; i--)
                    if (temporary[i][j] && temporary[i][j]==temporary[i-1][j])
                    {
                        score = score+temporary[i][j];
                        temporary[i][j]++;
                        temporary[i-1][j]=0;
                        changed=true;
                    }

            for (int j=0; j<4; j++)
            {
                int p = 3, q = 0;
                for (q=3; q>=0; q--) if (temporary[q][j]) temporary[p--][j]=temporary[q][j];
                for (; p>=0; p--) temporary[p][j] = 0;
            }
            break;
         //LEFT
        case 6:
            for (int i=0; i<4; i++)
            {
                signed p = 0, q = 0;
                for (; q<4; q++)
                    if (temporary[i][q])
                    {
                        if (p!=q) changed=true;
                        temporary[i][p++]=temporary[i][q];
                    }
                for (; p<4; p++) temporary[i][p] = 0;
            }

            for (int i=0; i<4; i++)
                for (int j=0; j<3; j++)
                    if (temporary[i][j] && temporary[i][j]==temporary[i][j+1])
                    {
                        score = score+temporary[i][j];
                        temporary[i][j]++;
                        temporary[i][j+1]=0;
                        changed=true;
                    }

            for (int i=0; i<4; i++)
            {
                int p = 0, q = 0;
                for (; q<4; q++) if (temporary[i][q]) temporary[i][p++]=temporary[i][q];
                for (; p<4; p++) temporary[i][p] = 0;
            }
            break;
        //RIGHT
        case 7:
            for (int i=0; i<4; i++)
            {
                int p = 3, q = 0;
                for (q=3; q>=0; q--)
                    if (temporary[i][q])
                    {
                        if (p!=q) changed=true;
                        temporary[i][p--]=temporary[i][q];
                    }
                for (; p>=0; p--) temporary[i][p] = 0;
            }

            for (int i=0; i<4; i++)
                for (int j=3; j>0; j--)
                    if (temporary[i][j] && temporary[i][j]==temporary[i][j-1])
                    {
                        score = score+temporary[i][j];
                        temporary[i][j]++;
                        temporary[i][j-1]=0;
                        changed=true;
                    }

            for (int i=0; i<4; i++)
            {
                signed p = 3, q = 0;
                for (q=3; q>=0; q--) if (temporary[i][q]) temporary[i][p--]=temporary[i][q];
                for (; p>=0; p--) temporary[i][p] = 0;
            }
            break;
    }
   if(!test)
     memcpy(table, temporary, sizeof(temporary));
   return changed;
  }
void jugame(){
  if(op(4,true) || op(5,true) || op(6,true) || op(7,true))
    return;
  
    gameover = true;
    total = score;

    
    
    if(ONENET.netWork&&gameover == true)
    {
        //上传数据
        if(gameover == true)                
        {
            
            if(sendFlag)
            {
                ONENET.OneNet_SendData(total);               //上传数据
            }
            
    
            
        }

        //错误处理
        if(FAULT.faultType != FAULT_NONE)                  //如果错误标志被设置
        {
            FAULT.Fault_Process();                        //进入错误处理函数
        }
    }
    else
    {   
        while(!ONENET.netWork){
        //网络连接 平台连接
        if(!NET_DEVICE.NET_DEVICE_Init())
            ONENET.OneNet_DevLink(ONENET.devID, ONENET.apiKey);
        
        delay(100);
        }
        
        //上传数据
        if(gameover == true)                
        {
            
            if(sendFlag)
            {
                ONENET.OneNet_SendData(total);               //上传数据
            }
            
    
            
        }

        //错误处理
        if(FAULT.faultType != FAULT_NONE)                  //如果错误标志被设置
        {
            FAULT.Fault_Process();                        //进入错误处理函数
        }
    
        
    }
    lcd.firstPage();
    lcd.setFont(u8g_font_ncenB14);
    lcd.setFontPosTop();
    do {
        lcd.drawStr(3,23,"GAME OVER");
    } while(lcd.nextPage());
    for(int i=4;i<=7;i++){
      if(digitalRead(i) == LOW){
          setup();
          
        }
      }
    
  
}
//在空置区域创建一个“2”
void createnum(){

  int empty[16]={0},emnum=0,test=0;
  for(int i=0;i<4;i++){
    for(int j=0;j<4;j++){
      if(table[i][j] == 0){
        empty[emnum++] = i*4+j; 
      }
    }
  }
  for(int i=0;i<16;i++){
    if(empty[i] != 0)
      test = 1;
  }
  if(test){
    int p = random(0, emnum);
    int x, y;
    x = empty[p]/4;
    y = empty[p]%4;
    table[x][y] = 1;
  }
}


void setup() {
  // put your setup code here, to run once:
    pinMode(4, INPUT_PULLUP);
    pinMode(5, INPUT_PULLUP);
    pinMode(6, INPUT_PULLUP);
    pinMode(7, INPUT_PULLUP);

    score = 0;
    NET_DEVICE.NET_DEVICE_IO_Init();
    NET_DEVICE.NET_DEVICE_Reset();
    NET_DEVICE.NET_DEVICE_Set_DataMode(0);
    gameover = false;
    memset(table, 0, sizeof(table));

    randomSeed(analogRead(A0));
    /*while(!ONENET.netWork){
        //网络连接 平台连接
        if(!NET_DEVICE.NET_DEVICE_Init())
            ONENET.OneNet_DevLink(ONENET.devID, ONENET.apiKey);
        
        delay(100);
        }*/


    
    createnum();
    createnum();
    Serial.begin(9600);
    lcd.begin();
    printable();

}

void loop() {
  // put your main code here, to run repeatedly:
  if(!gameover){
    for(int i=4;i<=7;i++){
      if(digitalRead(i) == LOW){
        if(op(i,true)){
          op(i);
          createnum();
          printable();
          
          jugame();
          juWin();
          delay(200);
        }
      }
    }
  }
}
